from functools import wraps
from random import random
import hashlib

from flask import abort, session, redirect, render_template as _render, Blueprint as _Blueprint, request

import requests
import json

base_url = 'http://localhost:1145'

def md5ify(data):
    md5 = hashlib.md5()
    md5.update(data.encode())
    return md5.hexdigest()

class FalseDict(dict):
    def __bool__(self):
        return False

class TrueDict(dict):
    def __bool__(self):
        return True

def render_template(template, **context):
    ret = _render(template, **context,
        error=session.get('error'),
        userid=session.get('id'),
        username=session.get('name'),
        usercls=session.get('cls'),
        userclsname=session.get('clsName'),
        userauth=session.get('auth')
    )
    if 'error' in session:
        session.pop('error')
    return ret

def _request(url, method, echo, headers, data):
    global error
    res = method(url, data=data, headers=headers)
    if res.status_code // 100 != 2:
        try:
            res = json.loads(res.text)
            error = res['message']
            return FalseDict(res)
        except json.decoder.JSONDecodeError:
            abort(res.status_code)
    else:
        res = json.loads(res.text)
        if res['type'] != 'SUCCESS':
            error = res['message']
            return FalseDict(res)
        return TrueDict(res)

def get(url, echo=True, **data):
    return _request(base_url + url, requests.get, echo, {'Authorization': session.get('token')}, data)

def post(url, echo=True, **data):
    return _request(base_url + url, requests.post, echo, {'Authorization': session.get('token')}, json.dumps(data))

class Blueprint(_Blueprint):
    def route(self, rule, auth=0xffff, **options):
        def wrap(func):
            @wraps(func)
            def wrapper(*args, **kwargs):
                if auth is not None:
                    if session.get('token') is None:
                        session['error'] = '未登录'
                        return redirect('/login')
                    if not authorized(auth):
                        session['error'] = '权限不足'
                        return redirect('/')
                return func(*args, **kwargs)
            _Blueprint.add_url_rule(self, rule, endpoint=md5ify(str(random())), view_func=wrapper, **options)
            return func
        return wrap

Categ = {
    0b1: '无',
    0b10: '学生',
    0b100: '教师',
    0b1000: '支书',
    0b10000: '管理员',
    0b100000: '审计员',
    0b1000000: '系统'
}

def auth2str(auth):
    return ', '.join((v for k, v in Categ.items() if k & auth))

def authorized(auth):
    return session.get('auth') & (auth | 64)

class Form:
    def __init__(self, **validators):
        self.__validators = validators

    def validate(self):
        for k, v in self.__validators.items():
            for i in v:
                if not i(request.form.get(k)):
                    self.message = i.message
                    return False
        return True

    def validate_on_submit(self, echo=True):
        if request.method in ('GET', 'DELETE'):
            return False
        ret = self.validate()
        if not ret:
            if echo:
                session['error'] = self.message
                print(self.message)
            return False
        return True

class Int:
    message = '必须为整数'

    def __new__(cls, field):
        try:
            int(field)
            return True
        except (ValueError, TypeError):
            return False

class Required:
    message = '不能为空'

    def __new__(cls, field):
        return len(field)

class Length:
    def __init__(self, length):
        self.__length = length

    def __call__(self, field):
        return len(field) == self.__length

    @property
    def message(self):
        return f'长度必须为{self.__length}'